package com.hd.hdxgddcommon.utils;

import com.hd.hdxgddcommon.custom.CallbackHttpRequestRetryHandler;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContextBuilder;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


/**
 * HTTP 请求工具类
 */

@Slf4j
public class HttpUtils {


    private static PoolingHttpClientConnectionManager connMgr;


    private static RequestConfig requestConfig;


    private static final int MAX_TIMEOUT = 7000;

    private static CloseableHttpClient httpClient;
    private static final int idleTimeout = 30;
    private static final int monitorInterval = 60;
    private static ScheduledExecutorService monitorExecutor;

    static {
        //创建自动管理cookie的httpClient
        ConnectionSocketFactory plainSocketFactory = PlainConnectionSocketFactory.getSocketFactory();
        // 跳过大华的ssl证书问题
        LayeredConnectionSocketFactory sslSocketFactory = new SSLSocketFactory(SSLContexts.createDefault(), SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);


        Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", plainSocketFactory)
                .register("https", sslSocketFactory)
                .build();

        // 设置连接池
        connMgr = new PoolingHttpClientConnectionManager(registry);
        // 设置连接池大小
        connMgr.setMaxTotal(100);
        connMgr.setDefaultMaxPerRoute(connMgr.getMaxTotal());
        RequestConfig.Builder configBuilder = buildDefaultConfigBuilder();
        // 在提交请求之前 测试连接是否可用
        //configBuilder.setStaleConnectionCheckEnabled(true);
        requestConfig = configBuilder.build();

        // httpsClient = HttpClients.custom().setConnectionManager(connMgr).setDefaultRequestConfig(requestConfig).setRetryHandler(new CallbackHttpRequestRetryHandler()).build();
        httpClient = HttpClients.custom().setConnectionManager(connMgr)
                .setDefaultRequestConfig(requestConfig)
                .setRetryHandler(new CallbackHttpRequestRetryHandler())
                .build();

        monitorExecutor = Executors.newScheduledThreadPool(1);
        monitorExecutor.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                //关闭异常连接
                connMgr.closeExpiredConnections();
                //关闭5s空闲的连接
                connMgr.closeIdleConnections(idleTimeout, TimeUnit.SECONDS);
                //  log.info("close expired and idle for over " + idleTimeout + "s connection");
            }
        }, monitorInterval, monitorInterval, TimeUnit.SECONDS);

    }

    private static RequestConfig.Builder buildDefaultConfigBuilder() {
        RequestConfig.Builder configBuilder = RequestConfig.custom();
        configBuilder.setCookieSpec(CookieSpecs.STANDARD_STRICT);
        // 设置连接超时
        configBuilder.setConnectTimeout(MAX_TIMEOUT);
        // 设置读取超时
        configBuilder.setSocketTimeout(MAX_TIMEOUT);
        // 设置从连接池获取连接实例的超时
        configBuilder.setConnectionRequestTimeout(MAX_TIMEOUT);
        // 在提交请求之前 测试连接是否可用
        //configBuilder.setStaleConnectionCheckEnabled(true);
        return configBuilder;
    }

    /**
     * 关闭连接池
     */
    public static void closeConnectionPool() {
        try {
            httpClient.close();
            connMgr.close();
            monitorExecutor.shutdown();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 发送 GET 请求(HTTP),不带输入数据
     *
     * @param url
     * @return
     */


    public static CloseableHttpResponse doGet(String url) {
        return doGet(url, new HashMap());
    }

    public static String doGetReturnString(String url) throws Exception {
        CloseableHttpResponse response = doGet(url);
        String result = null;
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            result = EntityUtils.toString(response.getEntity(), "utf-8");
            log.info("返回数据：>>>" + result);
        } else {
            log.info("请求失败！，url:" + url);
        }
        return result;
    }

    /**
     * 发送 GET 请求(HTTP),K-V形式
     *
     * @param url
     * @param params
     * @return
     */


    public static CloseableHttpResponse doGet(String url, Map<String, Object> params) {
        String apiUrl = url;
        StringBuffer param = new StringBuffer();
        int i = 0;
        for (String key : params.keySet()) {
            if (i == 0)
                param.append("?");
            else
                param.append("&");
            param.append(key).append("=").append(params.get(key));
            i++;
        }
        apiUrl += param;
        String result = null;
        try {

            HttpGet get = new HttpGet(apiUrl);
            CloseableHttpResponse response = httpClient.execute(get);
            return response;
//            int statusCode = response.getStatusLine().getStatusCode();
//            System.out.println("执行状态码 : " + statusCode);
//            HttpEntity entity = response.getEntity();
//            if (entity != null) {
//                InputStream instream = entity.getContent();
//                result = IOUtils.toString(instream, "UTF-8");
//            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 发送 POST 请求(HTTP),不带输入数据
     *
     * @param apiUrl
     * @return
     */


    public static CloseableHttpResponse doPost(String apiUrl) {
        return doPost(apiUrl, new HashMap());
    }


    /**
     * 发送 POST 请求(HTTP),K-V形式
     *
     * @param apiUrl API接口URL
     * @param params 参数map
     * @return
     */

    public static CloseableHttpResponse doPost(String apiUrl, Map<String, String> params, int timeout) {
        return doPost(apiUrl, null, params, timeout);
    }

    public static CloseableHttpResponse doPost(String apiUrl, Map<String, String> params) {
        return doPost(apiUrl, null, params, null);
    }


    public static CloseableHttpResponse doPost(String apiUrl, Map<String, String> header, Map<String, String> params, Integer timeout) {
        HttpPost httpPost = new HttpPost(apiUrl);
        if (header != null) {
            header.forEach((k, v) -> httpPost.addHeader(k, v));
        }

        CloseableHttpResponse response = null;
        try {
            if (timeout != null) {
                RequestConfig.Builder builder = buildDefaultConfigBuilder();
                builder.setSocketTimeout(timeout);
                builder.setConnectTimeout(timeout);
                RequestConfig config = builder.build();
                httpPost.setConfig(config);
            } else {
                httpPost.setConfig(requestConfig);
            }
            List pairList = new ArrayList(params.size());
            for (Map.Entry<String, String> entry : params.entrySet()) {
                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
                pairList.add(pair);
            }

            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("UTF-8")));

            response = httpClient.execute(httpPost);

            return response;

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
        }
        return response;
    }

    /**
     * 发送 POST 请求(HTTP),JSON形式
     *
     * @param apiUrl
     * @param json   json对象
     * @return
     */


    public static CloseableHttpResponse doPost(String apiUrl, String json) {

        String httpStr = null;

        HttpPost httpPost = new HttpPost(apiUrl);

        CloseableHttpResponse response = null;

        try {

            httpPost.setConfig(requestConfig);

            StringEntity stringEntity = new StringEntity(json, "UTF-8");//解决中文乱码问题

            stringEntity.setContentEncoding("UTF-8");

            stringEntity.setContentType("application/json");

            httpPost.setEntity(stringEntity);

            response = httpClient.execute(httpPost);

            return response;

//            HttpEntity entity = response.getEntity();
//
//            System.out.println(response.getStatusLine().getStatusCode());
//
//            httpStr = EntityUtils.toString(entity, "UTF-8");

        } catch (IOException e) {
            e.printStackTrace();
        } finally {

        }

        return response;

    }


//    public static CloseableHttpResponse doPostSSL(String apiUrl) {
//        return doPostSSL(apiUrl, new HashMap<>());
//    }
//
//
//    /**
//     * 发送 SSL POST 请求(HTTPS),K-V形式
//     *
//     * @param apiUrl API接口URL
//     * @param params 参数map
//     * @return
//     */
//
//
////    public static CloseableHttpResponse doPostSSL(String apiUrl, Map<String, String> params) {
////        HttpPost httpPost = new HttpPost(apiUrl);
////        CloseableHttpResponse response = null;
////        String httpStr = null;
////        try {
////            httpPost.setConfig(requestConfig);
////            List pairList = new ArrayList(params.size());
////            for (Map.Entry<String, String> entry : params.entrySet()) {
////
////                NameValuePair pair = new BasicNameValuePair(entry.getKey(), entry.getValue());
////
////                pairList.add(pair);
////
////            }
////            httpPost.setEntity(new UrlEncodedFormEntity(pairList, Charset.forName("utf-8")));
////            response = httpsClient.execute(httpPost);
////            return response;
////        } catch (Exception e) {
////            e.printStackTrace();
////        } finally {
////        }
////        return response;
////    }

    public static String respToString(CloseableHttpResponse response) {
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode != HttpStatus.SC_OK) {
            return null;
        }
        HttpEntity entity = response.getEntity();
        if (entity == null) {
            return null;
        }
        String httpStr = null;
        try {
            httpStr = EntityUtils.toString(entity, Charset.forName("utf-8"));
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (response != null) {
                try {
                    EntityUtils.consume(response.getEntity());
                } catch (IOException e) {

                    e.printStackTrace();
                }
            }
        }
        return httpStr;
    }


    /**
     * 发送 SSL POST 请求(HTTPS),JSON形式
     *
     * @param apiUrl API接口URL
     * @param json   JSON对象
     * @return
     */

//
//    public static CloseableHttpResponse doPostSSL(String apiUrl, String json) {
//
//        HttpPost httpPost = new HttpPost(apiUrl);
//
//        CloseableHttpResponse response = null;
//
//        String httpStr = null;
//
//        try {
//
//            httpPost.setConfig(requestConfig);
//
//            StringEntity stringEntity = new StringEntity(json, "UTF-8");//解决中文乱码问题
//
//            stringEntity.setContentEncoding("UTF-8");
//
//            stringEntity.setContentType("application/json");
//
//            httpPost.setEntity(stringEntity);
//
//            response = httpsClient.execute(httpPost);
//
//            return response;
//        } catch (Exception e) {
//            e.printStackTrace();
//        } finally {
//        }
//        return null;
//    }


    /**
     * 创建SSL安全连接
     *
     * @return
     */
    public static LayeredConnectionSocketFactory createSSLClientDefault() {
        try {
            SSLContext sslContext = new SSLContextBuilder().loadTrustMaterial(null, new TrustStrategy() {
                //信任所有
                public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                    return true;
                }
            }).build();
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
            return sslsf;
        } catch (KeyManagementException e) {
            e.printStackTrace();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyStoreException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 发送 Delete 请求(HTTP),K-V形式
     *
     * @param url
     * @param params
     * @return
     */
    public static CloseableHttpResponse doDelete(String url, Map<String, Object> params) {
        String apiUrl = url;
        StringBuffer param = new StringBuffer();
        int i = 0;
        for (String key : params.keySet()) {
            if (i == 0)
                param.append("?");
            else
                param.append("&");
            param.append(key).append("=").append(params.get(key));
            i++;
        }
        apiUrl += param;
        try {

            HttpDelete httpDelete = new HttpDelete(apiUrl);
            return httpClient.execute(httpDelete);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 发送 Delete 请求(HTTP),url 拼接参数形式
     *
     * @param url
     * @param paramSuffix
     * @return
     */
    public static CloseableHttpResponse doDelete(String url, String paramSuffix) {

        String apiUrl = url;
        apiUrl += paramSuffix;
        try {
            HttpDelete httpDelete = new HttpDelete(apiUrl);
            return httpClient.execute(httpDelete);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}